﻿/* Copyright (C) 2012 by John Cronin
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:

 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace davserv
{
    class Encoding
    {
        static Dictionary<string, string> guess_encoding;

        static Encoding()
        {
            guess_encoding = new Dictionary<string, string>();

            guess_encoding[".html"] = "text/html";
            guess_encoding[".htm"] = "text/html";
            guess_encoding[".txt"] = "text/plain";
            guess_encoding[".h"] = "text/plain";
            guess_encoding[".c"] = "text/plain";
            guess_encoding[".xml"] = "text/xml";
            guess_encoding[".gif"] = "image/gif";
            guess_encoding[".jpeg"] = "image/jpeg";
            guess_encoding[".jpg"] = "image/jpeg";
            guess_encoding[".png"] = "image/png";
            guess_encoding[".tiff"] = "image/tiff";

        }

        const string DefaultMimeType = "text/plain";

        public static Backend.ByteResponse GetEncoding(HttpServer.Request r)
        {
            Backend.ByteResponse ret = new Backend.ByteResponse { Value = r.Body, ContentType = DefaultMimeType };

            if (r.Headers.ContainsKey("Content-Type"))
                ParseContentType(ret, r.Headers["Content-Type"]);
            else
            {
                // attempt to guess

                string lower = r.RequestURI.ToLower();

                foreach (KeyValuePair<string, string> kvp in guess_encoding)
                {
                    if (lower.EndsWith(kvp.Key))
                    {
                        ret.ContentType = kvp.Value;
                        break;
                    }
                }
            }

            if (ret.Encoding == null)
                ParseEncoding(ret, r);

            return ret;
        }

        private static void ParseEncoding(Backend.ByteResponse ret, HttpServer.Request r)
        {
            // try to get the charset of a text file

            string ctype = ret.ContentType;
            string[] lines = System.Text.Encoding.UTF8.GetString(r.Body).Split('\n');

            // interpret an xml header if there is one
            if (ctype.EndsWith("/xml"))
            {
                if (lines[0].StartsWith("<?xml"))
                {
                    int enc_start = lines[0].IndexOf("encoding=\"");
                    if (enc_start != -1)
                    {
                        string enc = lines[0].Substring(enc_start + "encoding=\"".Length);
                        int enc_end = enc.IndexOf("\"");
                        if (enc_end != -1)
                            ret.Encoding = enc.Substring(0, enc_end);
                    }
                }
            }

            if (ret.Encoding != null)
                return;

            if (ctype.StartsWith("text/"))
            {
                try
                {
                    if ((r.Body[0] == 0xef) && (r.Body[1] == 0xbb) && (r.Body[2] == 0xbf))
                        ret.Encoding = "utf-8";
                    else if ((r.Body[0] == 0xfe) && (r.Body[1] == 0xff))
                        ret.Encoding = "utf-16be";
                    else if ((r.Body[0] == 0xff) && (r.Body[1] == 0xfe))
                        ret.Encoding = "utf-16";
                    else if ((r.Body[0] == 0x00) && (r.Body[1] == 0x00) && (r.Body[2] == 0xfe) && (r.Body[3] == 0xff))
                        ret.Encoding = "utf-32be";
                    else if ((r.Body[0] == 0xff) && (r.Body[1] == 0xfe) && (r.Body[2] == 0x00) && (r.Body[3] == 0x00))
                        ret.Encoding = "utf-32";
                }
                catch (Exception)
                { }

                if (ret.Encoding == null)
                    ret.Encoding = "utf-8";
            }
        }

        private static void ParseContentType(Backend.ByteResponse ret, string ctypeheader)
        {
            throw new NotImplementedException();
        }
    }
}
